package xorm

import (
	"gitee.com/stevenchin/gin_study/xorm/initxorm"
	"github.com/gin-gonic/gin"
	"github.com/xormplus/xorm"
	"net/http"
)

/*
事务处理。支持简单事务模型和嵌套事务模型（支持类JAVA Spring的事务传播机制）
*/

// 一. 简单事务使用
//	   大多数情况下使用简单事务模型来进行事务处理。当使用简单事务模型进行事务处理时，需要创建Session对象，另外当使用Sql()、
//     SqlMapClient()、SqlTemplateClient()方法进行操作时也推荐手工创建Session对象方式管理Session。在进行事物处理时可以混用
//     ORM方法和RAW方法
func SimpleTransaction(ctx *gin.Context) {

	session := initxorm.Engine.NewSession()
	// 延迟关闭事务
	defer func(session *xorm.Session) {
		err := session.Close()
		if err != nil {

		}
	}(session)
	// 创建一个事务
	err := session.Begin()
	if err != nil {
		ctx.String(http.StatusInternalServerError, "transaction begin error: "+err.Error())
	}
	b := basic{
		Name:     "stevenQin",
		Age:      20,
		Password: "myPassword",
	}
	if _, err = session.Insert(&b); err != nil {
		// 回滚事务
		_ = session.Rollback()
		ctx.String(http.StatusInternalServerError, "insert error: "+err.Error())
	}
	b.Name = "我把名字更新了"
	if _, err = session.ID(b.Id).Update(&b); err != nil {
		_ = session.Rollback()
		ctx.String(http.StatusInternalServerError, "update error: "+err.Error())
	}
	if _, err = session.ID(b.Id).Delete(&basic{}); err != nil {
		_ = session.Rollback()
		ctx.String(http.StatusInternalServerError, "delete error: "+err.Error())
	}
	// 提交事务
	if err = session.Commit(); err != nil {
		ctx.String(http.StatusInternalServerError, "transaction commit error: "+err.Error())
	}

	ctx.String(http.StatusOK, "transaction success")
}

//二. 嵌套事务模型使用
//	  使用嵌套事务模型进行事务处理时候，使用session.BeginTrans()创建嵌套事务时，将返回Transaction实例，后续操作则在同一个
//	  Transaction实例下操作。在进行具体数据库操作时候，则使用tx.Session()API可以获得当前事务所持有的session会话，从而进行
//	  Get()，Find()，Execute()等具体数据库操作
//    TIPS，一下两点示例没列举到。但是要知道用处:
//	  	1. SavePoint(savePointID string)，设置SavePoint：tx.SavePoint("xorm_save")；
//		2. RollbackToSavePoint(savePointID string)，回滚至SavePoint：tx.RollbackToSavePoint("xorm_save")
func NestTransaction(ctx *gin.Context) {

	session := initxorm.Engine.NewSession()
	// 延迟关闭事务
	defer func(session *xorm.Session) {
		err := session.Close()
		if err != nil {

		}
	}(session)
	// 创建一个嵌套事务（默认创建事务类型为 PROPAGATION_REQUIRED）
	transaction, err := session.BeginTrans()
	// session.BeginTrans(xorm.PROPAGATION_SUPPORTS) //创建事务类型为 PROPAGATION_SUPPORTS。
	// TIPS：事务类型具体介绍见：https://www.kancloud.cn/xormplus/xorm/235728
	if err != nil {
		ctx.String(http.StatusInternalServerError, "transaction begin error: "+err.Error())
	}
	b := basic{
		Name:     "stevenQin",
		Age:      20,
		Password: "myPassword",
	}
	//  transaction.Session()：获得当前事务所在Session，以便进行后续数据库操作，当PROPAGATION_REQUIRES_NEW或PROPAGATION_NOT_SUPPORTED
	//  类型事务时候，都有可能创建新Session进行后续操作，该函数可以获得这个新Session。建议事务中都使用本函数获取Session进行后续操作
	if _, err = transaction.Session().Insert(&b); err != nil {
		// 回滚事务
		_ = transaction.RollbackTrans()
		ctx.String(http.StatusInternalServerError, "insert error: "+err.Error())
	}
	b.Name = "我把名字更新了"
	if _, err = transaction.Session().ID(b.Id).Update(&b); err != nil {
		_ = transaction.RollbackTrans()
		ctx.String(http.StatusInternalServerError, "update error: "+err.Error())
	}
	if _, err = transaction.Session().Exec("delete from basic where name = ?", b.Name); err != nil {
		_ = transaction.RollbackTrans()
		ctx.String(http.StatusInternalServerError, "delete error: "+err.Error())
	}
	// 再次删除将报错
	if _, err = transaction.Session().ID(b.Id).Delete(&basic{}); err != nil {
		_ = transaction.RollbackTrans()
		ctx.String(http.StatusInternalServerError, "delete error: "+err.Error())
	}
	// 提交事务
	if err = transaction.CommitTrans(); err != nil {
		ctx.String(http.StatusInternalServerError, "transaction commitTrans error: "+err.Error())
	}

	ctx.String(http.StatusOK, "transaction success")
}

//三. 八种事务类型及事务传播机制。具体介绍可查阅：https://www.kancloud.cn/xormplus/xorm/235728

//四. 嵌套事务示例代码。可见：https://www.kancloud.cn/xormplus/xorm/235735
